**************************************************************************
*
*			      PACMAN
*		(c) W.Barnes, August-September 1991.
*
**************************************************************************

	opt	O+,OW-		all optimising on, warnings off

**************************************************************************
* CONSTANTS
**************************************************************************

* system variable locations
KEYCLICK	equ	$484	
H_PAL		equ	$ffff8240
H_RES		equ	$ffff8260
KB_CONTROL	equ	$fffffc00
KB_DATA		equ	$fffffc02
VBI		equ	$70

* colour numbers of objects
SPACE		equ	0
WALL		equ	10
TRACK		equ	11
ENERGIZER	equ	14
DOT		equ	15

*************************************************************************
* offsets to sprite and other data.  a6 is the index register
pacman_data	rs.w	0
pacman_x	rs.w	1
pacman_y	rs.w	1
pacman_stats	rs.w	1
pacman_dir	rs.w	1
ghost_data	rs.w	0
shadow_data	rs.w	0
shadow_x	rs.w	1
shadow_y	rs.w	1
shadow_stats	rs.w	1
shadow_dir	rs.w	1
pokey_data	rs.w	0
pokey_x		rs.w	1
pokey_y		rs.w	1
pokey_stats	rs.w	1
pokey_dir	rs.w	1
speedy_data	rs.w	0
speedy_x	rs.w	1
speedy_y	rs.w	1
speedy_stats	rs.w	1
speedy_dir	rs.w	1
bashful_data	rs.w	0
bashful_x	rs.w	1
bashful_y	rs.w	1
bashful_stats	rs.w	1
bashful_dir	rs.w	1
rnd_num		rs.w	1
old_pal		rs.w	16
old_physbase	rs.l	1
old_logbase	rs.l	1
old_ssp		rs.l	1
old_vbi		rs.l	1
j_pack_addr	rs.l	1
old_j_pack	rs.l	1
score		rs.l	1
hiscore		rs.l	1
energizer_time	rs.w	1
ghost_blue	rs.w	1
ghost_value	rs.w	1
scrn_delay	rs.w	1
fruit_type	rs.w	1
fruit_value	rs.w	1
fr_spr_off	rs.w	1
fruit_appear	rs.w	1
fruit_disappear	rs.w	1
screen_num	rs.w	1
time		rs.w	1
physbase	rs.l	1
logbase		rs.l	1
backbase	rs.l	1
fruit_on	rs.b	1
num_dots_eaten	rs.b	1
ghosts_stop	rs.b	1
old_res		rs.b	1
var_length	rs.w	0
*************************************************************************
	
* initial values
PACMAN_START_X		equ	148
PACMAN_START_Y		equ	134
PACMAN_START_DIR	equ	0
POKEY_START_X		equ	129
POKEY_START_Y		equ	75
POKEY_START_DIR		equ	1
SHADOW_START_X		equ	148
SHADOW_START_Y		equ	62
SHADOW_START_DIR	equ	0
BASHFUL_START_X		equ	148
BASHFUL_START_Y		equ	84
BASHFUL_START_DIR	equ	2
SPEEDY_START_X		equ	166
SPEEDY_START_Y		equ	75
SPEEDY_START_DIR	equ	0

START_LIVES		equ	3
SPRITE_SPEED		equ	1

**************************************************************************
* MACROS

crawio	macro	[ascii code]
	 move.w	\1,-(a7)		char code, 255=inkey
	 move.w	#6,-(a7)		crawio()
	 trap	#1			gemdos
	 addq.l	#4,a7			tidy
	endm

do_snd	macro	[label of sound data]
	 pea	\1(pc)
	 move.w	#32,-(a7)	dosound()
	 trap	#14		xbios
	 addq.l	#6,a7		tidy
	endm

inkey	macro
	 crawio <#255>
	endm
	
**************************************************************************
****************************** MAIN PROGRAM ******************************
**************************************************************************
* global	a6: base address of almost all of the variables
**************************************************************************
	lea	all_data,a6	base address of all the data
* go to supervisor mode	
	clr.l	-(a7)	
	move.w	#32,-(a7)
	trap	#1		gemdos
	addq.l	#6,a7		tidy
	move.l	d0,old_ssp(a6)
* work out screen addresses	
	move.w	#2,-(a7)	physbase()
	trap	#14		xbios
	addq.l	#2,a7		tidy
	move.l	d0,physbase(a6)
	move.l	d0,old_physbase(a6)
	move.w	#3,-(a7)	logbase()
	trap	#14		xbios	
	addq.l	#2,a7		tidy
	move.l	d0,old_logbase(a6)
	move.l	#log_scr,d0	find address of second screen
	addi.l	#$ff,d0		ensure that it's on a 256 boundary
	andi.b	#$00,d0
	move.l	d0,logbase(a6)
	addi.l	#32000,d0	background screen is above the log screen
	move.l	d0,backbase(a6)
	movem.l	H_PAL,d0-d7	save the old palette
	movem.l	d0-d7,old_pal(a6)
	move.b	H_RES,old_res(a6) save the old screen resolution
	clr.w	-(a7)		set low resolution
	move.l	physbase(a6),-(a7)
	move.l	physbase(a6),-(a7)
	move.w	#5,-(a7)
	trap	#14			xbios
	lea	12(a7),a7
	bsr	_black_screen
	bclr.b	#0,(KEYCLICK).w		turn off keyboard click
	move.l	(VBI).w,old_vbi(a6)
	move.l	#_new_vbi_routine,(VBI).w

	move.w	#34,-(a7)		kbdvbas(): get system vectors
	trap	#14			xbios
	addq.l	#2,a7
	move.l	d0,a0			address of system vectors
	lea	24(a0),a0		move to joystick vector
	move.l	a0,j_pack_addr(a6)	store the address of the vector
	move.l	(a0),old_j_pack(a6)	store the old vector
	move.l	#_joy_handler,(a0)	patch in the new one
js_loop	btst.b	#1,KB_CONTROL		is keyboard ready for command
	beq.s	js_loop			no, loop
	move.b	#$15,KB_DATA		set joy to, request packet mode

	bra	main_game

finish	
	btst.b	#1,KB_CONTROL		is keyboard ready for command
	beq.s	finish			no, loop
	move.b	#$8,KB_DATA		set mouse relative mode
	do_snd	<stop_music>
	move.l	j_pack_addr(a6),a0
	move.l	old_j_pack(a6),(a0)	put old joystick handler back
	bset.b	#0,(KEYCLICK).w		turn on keyboard click
	movem.l	old_pal(a6),d0-d7	reset the old palette
	movem.l	d0-d7,H_PAL
	move.l	old_vbi(a6),(VBI).w
	move.l	old_ssp(a6),a7
	move.b	old_res(a6),d0
	ext.w	d0
	move.w	d0,-(a7)		original resolution
	move.l	old_physbase(a6),-(a7)
	move.l	old_logbase(a6),-(a7)
	move.w	#5,-(a7)		setscreen()
	trap	#14			xbios
	lea	12(a7),a7		tidy
* exit the program
	clr.w	-(a7)			pterm0
	trap	#1			gemdos
**************************************************************************
_new_vbi_routine
	st	vbi_done
	rte
**************************************************************************
_wait_vbi
	tst.b	vbi_done
	beq.s	_wait_vbi
	rts
**************************************************************************
_swap_screens
	move.l	logbase(a6),d0
	move.l	physbase(a6),logbase(a6)
	move.l	d0,physbase(a6)
	lsr.w	#8,d0
	move.l	d0,$ffff8200.w
	sf	vbi_done
	rts
**************************************************************************
_black_screen
	movea.l	#H_PAL,a0
	moveq	#7,d0			8 long words = 16 words to do
black_loop
	clr.l	(a0)+			set to colour zero (black)
	dbf	d0,black_loop
	rts
**************************************************************************
_joy_handler
	sf	fire		set fire to false
	move.w	d0,-(a7)
	clr.w	d0
	move.b	1(a0),d0	F...RLDU
	add.b	d0,d0		...RLUD.	*2 for lookup table
	scs	fire		set fire to true if bit 7 set
	add.b	d0,d0		..RLDU..
	move.l	jlt(pc,d0.w),dxy_joy
	move.w	(a7)+,d0
	rts
*	       dx,dy		the bits	impossible cases	
jlt	dc.w	0,0		..0000..
	dc.w	0,-1		..000U..
	dc.w	0,1		..00D0..
	dc.w	0,0		..00DU..	*
	dc.w	-1,0		..0L00..
	dc.w	-1,-1		..0L0U..
	dc.w	-1,1		..0LD0..
	dc.w	-1,0		..0LDU..	*
	dc.w	1,0		..R000..	*
	dc.w	1,-1		..R00U..
	dc.w	1,1		..R0D0..
	dc.w	1,0		..R0DU..	*
	dc.w	0,0		..RL00..	*
	dc.w	0,-1		..RL0U..	*
	dc.w	0,1		..RLD0..	*
	dc.w	0,0		..RLDU..	*
**************************************************************************
_fade_out
	move.w	#%1110111011101110,d2
	moveq	#3,d0			4 bit planes to do
fo_pal_loop
	moveq	#15,d1
	movea.l	#H_PAL,a0
fo_col_loop
	bsr	_short_delay
	and.w	d2,(a0)+		mask out 1 bit plane, low
	dbf	d1,fo_col_loop
	rol.l	#1,d2
	dbf	d0,fo_pal_loop
	rts
**************************************************************************
_fade_in
	movea.l	#H_PAL,a0
	lea	def_pal(pc),a1
	move.w	#$7,d1
fade_pal_loop
	moveq	#0,d0
fade_col_loop		
	bsr	_short_delay
	move.w	0(a1,d0.w),d2
	sub.w	#$111,d2
	cmp.w	0(a0,d0.w),d2
	ble.s	fade_full
	 add.w	#$111,0(a0,d0.w)	increase by one grey scale
	 bra.s	f_next_reg
fade_full
	move.w	0(a1,d0.w),0(a0,d0.w)	transfer the exact colour
f_next_reg
	addq.w	#2,d0			next colour register
	cmpi.w	#30,d0
	ble.s	fade_col_loop
	dbf	d1,fade_pal_loop
	rts
**************************************************************************
main_game
	do_snd	<intro_song>
* title screen
* first clear the screen
	movea.l	physbase(a6),a0
	move.w	#7999,d0
ts_cls_loop
	clr.l	(a0)+
	dbf	d0,ts_cls_loop
* then copy the title picture over	
	movea.l	physbase(a6),a0
	lea	title_screen,a1
	move.w	#1599,d0		40 lines * 40 words per line
ts_cpy_loop
	move.l	(a1)+,(a0)+
	dbf	d0,ts_cpy_loop
* now the text
	lea	instructions(pc),a3
	bsr	_print
* show the screen		
	movem.l	title_pal,d0-d7
	movem.l	d0-d7,H_PAL
* load in the background screen (in .PC1 format)
	lea	backfile(pc),a0		address of the filename
	movea.l	backbase(a6),a1		where to write to
	bsr	_load_pc1		load the picture and decompress
* wait for a key to be pressed
	bsr	_get_key_colour
**************************************************************************
start_game
* check if there is a new high score
	move.l	score(a6),d0
	cmp.l	hiscore(a6),d0		is score greater than high score?
	ble.s	no_new_high
	 move.l	d0,hiscore(a6)		new high score
no_new_high
	move.w	#-1,screen_num(a6)
	move.w	#START_LIVES,pacman_stats(a6)	
	clr.l	score(a6)		score starts at zero				
start_round
	clr.w	time(a6)		time starts at zero
	addq.w	#1,screen_num(a6)	new screen for a new round
	bsr	_draw_all_dots
	bsr	_initial_round_values
start_new_life
	do_snd	<stop_music>
	tst.w	pacman_stats(a6)	0 lives left?
	bgt.s	more_lives_left
	 bsr	_game_over
	 bra.s	start_game
more_lives_left
	bsr	_fade_out
	sf	fruit_on(a6)		fruit off
	clr.w	energizer_time(a6)	energizer off
	clr.b	ghosts_stop(a6)		ghosts are not stopped
	move.w	#20,ghost_value(a6)	ghost value starts at 200
	clr.w	shadow_stats(a6)	ghosts start with normal attributes
	clr.w	pokey_stats(a6)
	clr.w	speedy_stats(a6)
	clr.w	bashful_stats(a6)
	bsr	_new_status_line
	bsr	_display_score
	bsr	_display_hiscore
	bsr	_copy_background_over
**************************************************************************
	move.w	#PACMAN_START_X,pacman_x(a6)
	move.w	#PACMAN_START_Y,pacman_y(a6)
	move.w	#PACMAN_START_DIR,pacman_dir(a6)				
	move.w	#POKEY_START_X,pokey_x(a6)	
	move.w	#POKEY_START_Y,pokey_y(a6)
	move.w	#POKEY_START_DIR,pokey_dir(a6)				
	move.w	#SHADOW_START_X,shadow_x(a6)	
	move.w	#SHADOW_START_Y,shadow_y(a6)
	move.w	#SHADOW_START_DIR,shadow_dir(a6)				
	move.w	#BASHFUL_START_X,bashful_x(a6)	
	move.w	#BASHFUL_START_Y,bashful_y(a6)
	move.w	#BASHFUL_START_DIR,bashful_dir(a6)				
	move.w	#SPEEDY_START_X,speedy_x(a6)	
	move.w	#SPEEDY_START_Y,speedy_y(a6)
	move.w	#SPEEDY_START_DIR,speedy_dir(a6)				
* copy new data to old data
	movea.l	a6,a1			get base of sprite data
	lea	old_spr_data,a0
	moveq	#9,d0			40 bytes = 10 long words to do
copy_init_spr_data
	move.l	(a1)+,(a0)+
	dbf	d0,copy_init_spr_data
**************************************************************************
* initial screen
	bsr	_display_sprites
	bsr	_swap_screens
	bsr	_fade_in
	bsr	_long_delay
	bsr	_new_status_line
**************************************************************************
* The main game
**************************************************************************
game_turn
* delay to make the earlier screens slower
	bsr	_screen_delay
* Transfer sprite data to the logical screen
	bsr	_wait_vbi
	bsr	_clear_screen
* copy new data to old data
	movea.l	a6,a1			get base of sprite data
	lea	old_spr_data,a0
	moveq	#9,d0			40 bytes = 10 long words to do
copy_spr_data
	move.l	(a1)+,(a0)+
	dbf	d0,copy_spr_data
**************************************************************************
* Actual game mechanics
**************************************************************************
* see if pacman wants to move
	movem.w	pacman_data(a6),d4-d7	get x,y,stats,dir
	bsr	_check_exits		get exits in d3: ....DURL
	movem.w	dxy_joy,d0-d1
	move.w	d7,d2			save current direction in d2
	cmpi.w	#1,d0			joystick right
	bne.s	pc_njrt
	 moveq	#1,d7			set new direction to right
	 bra.s	pac_go
pc_njrt	cmpi.w	#-1,d0			joystick left
	bne.s	pc_njlt		
	 moveq	#0,d7			set new direction to left
	 bra.s	pac_go
pc_njlt	cmpi.w	#-1,d1			joystick up
	bne.s	pc_njup
	 moveq	#2,d7			set new direction to up
	 bra.s	pac_go
pc_njup	cmpi.w	#1,d1			joystick down
	bne.s	pc_njdn
	 moveq	#3,d7			set new direction to down
	 bra.s	pac_go
pc_njdn	tst.b	fire			was the fire button pressed?
	beq.s	pc_njfire
	 bra.s	pac_go
pc_njfire
	cmpi.b	#$61,KB_DATA		<Undo;gt; to quit
	beq	finish
pac_go	
	btst	d7,d3			can the pacman go where he wants?
	beq.s	pac_can_go		ok, then go
	btst	d2,d3			can he cont in original direction?
	bne.s	pac_end			if not then don't move at all
	move.w	d2,d7			new dir = original dir
pac_can_go
	cmpi.w	#0,d7			going left
	bne.s	pc_nolt
	 subq.w	#SPRITE_SPEED,d4	subtract speed from x
	 bra.s	pac_end	
pc_nolt	cmpi.w	#1,d7			going right
	bne.s	pc_nort
	 addq.w	#SPRITE_SPEED,d4	add speed to x
	 bra.s	pac_end
pc_nort	cmpi.w	#2,d7			going up
	bne.s	pc_noup
	 subq.w	#SPRITE_SPEED,d5	subtract speed from y
	 bra.s	pac_end
pc_noup	
	 addq.w	#SPRITE_SPEED,d5	must be going down, add speed to y
pac_end	
* check if pacman ate a dot or energizer
	bsr	_check_dot_eaten
* check if pacman has gone through the tunnel
	cmpi.w	#32,d4			if x<=48 then out left tunnel
	bgt.s	pc_no_lt_tunnel
	 move.w	#260,d4			put him on the right side
	 bra.s	pc_end_tunnel	
pc_no_lt_tunnel
	cmpi.w	#264,d4			if x>=264 then out right tunnel
	blt.s	pc_end_tunnel
	 move.w	#36,d4			put him on the left side
pc_end_tunnel
	movem.w	d4-d7,pacman_data(a6)	return altered sprite data	
**************************************************************************
* move shadow
	movem.w	shadow_data(a6),d4-d7	get x,y,stats,dir
* find if the monster is not in the pen
	cmpi.w	#129,d4				
	blt.s	sh_int
	cmpi.w	#170,d4
	bge.s	sh_int
	cmpi.w	#75,d5
	blt.s	sh_int
	cmpi.w	#84,d5
	bge.s	sh_int	
	 move.w	#$700,H_PAL+2		back to red
	 bsr	_pen_intelligence
	 bra.s	done_sh_move
sh_int	btst	#0,d6			is Shadow just eyes
	beq.s	sh_not_i
	 bsr	_eye_intelligence
	 bra.s	done_sh_move	
sh_not_i
	tst.w	energizer_time(a6)	is pacman energized
	beq.s	sh_chase		if not then chase him
	 bsr	_shy_intelligence
	 bra.s	done_sh_move
sh_chase
	bsr	_intelligence
done_sh_move
	movem.w	d4-d7,shadow_data(a6)
**************************************************************************
* move bashful
	movem.w	bashful_data(a6),d4-d7
* find if the monster is not in the pen
	cmpi.w	#129,d4				
	blt.s	bs_int
	cmpi.w	#170,d4
	bge.s	bs_int
	cmpi.w	#75,d5
	blt.s	bs_int
	cmpi.w	#84,d5
	bge.s	bs_int	
	 move.w	#$057,H_PAL+18		back to light blue
	 bsr	_pen_intelligence
	 bra.s	done_bs_move
bs_int		
	btst	#0,d6
	beq.s	bs_not_i
	 bsr	_eye_intelligence
	 bra.s	done_bs_move
bs_not_i
	bsr	_shy_intelligence
done_bs_move
	movem.w	d4-d7,bashful_data(a6)
**************************************************************************
* move Speedy
	bsr	_move_speedy
**************************************************************************
* Choice move: Speedy or Pokey
	move.w	time(a6),d0
	and.w	#$f,d0			time mod 16
	cmpi.w	#1,d0			every 16 times move Speedy
	bne.s	move_pokey_not_speedy
	 bsr	_move_speedy
	 bra.s	check_for_collision
move_pokey_not_speedy
	bsr	_move_pokey
**************************************************************************
check_for_collision
	move.w	pacman_x(a6),d4
	move.w	pacman_y(a6),d5
	lea	ghost_data(a6),a0	
	moveq	#3,d6			four ghosts to do
chk_coln_loop
	movem.w	(a0),d0-d2		get ghost x,y,stats
	bsr	_check_collision
	tst.b	d3
	beq.s	done_g_coln
	 move.w d2,d0
	 andi.w	#%11,d0
	 tst.w	d0			ghost normal? (ie d0=%00)
	 bne.s	coln_n_n
	  bsr	_pacman_dead
	  bra	start_new_life
coln_n_n cmpi.w	#%10,d0			ghost blue?
	 bne.s	done_g_coln
	  bset	#0,d2			set stats, got the ghost
	  bclr	#1,d2			so he's not blue
	  move.w d2,4(a0)		put stats back
	  move.w ghost_value(a6),d0	increase the score
	  ext.l	d0
	  add.l	d0,score(a6)
	  add.w	d0,d0			double the ghost value
	  move.w d0,ghost_value(a6)	and put it back
	  bsr	_display_score
done_g_coln
	addq.l	#8,a0			next ghost data
	dbf	d6,chk_coln_loop
* now check if pacman has got the fruit
	tst.b	fruit_on(a6)		fruit there?
	beq.s	done_f_coln		no need to check if not
	 cmpi.w	#98,d5			check y
	 bne.s	done_f_coln
	  cmpi.w #138,d4		check x left bound
	  blt.s	done_f_coln
	   cmpi.w #158,d4		check x right bound
	   bgt.s done_f_coln
* got the fruit
	    tst.w energizer_time(a6)	only make sound if eng off		
	    bgt.s no_fruit_sound
	    do_snd <fruit_sound>
no_fruit_sound
	    moveq #0,d0
	    move.w fruit_value(a6),d0
	    add.l d0,score(a6)
	    bsr	_display_score
	    sf	fruit_on(a6)		turn the fruit off
done_f_coln
**************************************************************************
* force a joystick interupt to occur
jr_loop
	btst.b	#1,KB_CONTROL	is keyboard ready for command
	beq.s	jr_loop		no, loop
	move.b	#$16,KB_DATA	request a joystick packet

	bsr	_display_sprites
	bsr	_swap_screens

	tst.b	ghosts_stop(a6)		ghosts stopped?
	beq.s	no_ghost_stop
	 subq.b	#1,ghosts_stop(a6)	one less frame to stop
no_ghost_stop
	tst.w	energizer_time(a6)	energizer off?
	beq.s	no_eng_dec		if so don't change
	 cmpi.w	#100,energizer_time(a6)	last few moments of energizer?
	 bgt.s	eng_no_flash
	  bsr	_flash_ghosts
eng_no_flash	
	 subq.w	#1,energizer_time(a6)	less time to chase ghosts
	 bgt.s	no_eng_dec
	  bsr	_energizer_off		if -1 then end of time
no_eng_dec
	addq.w	#1,time(a6)		increase time
	move.w	time(a6),d0		check the time
	cmp.w	fruit_appear(a6),d0	time to turn the fruit on?
	bne.s	no_fruit_appear
	 st	fruit_on(a6)
no_fruit_appear
	cmp.w	fruit_disappear(a6),d0
	bne.s	next_game_turn
	 sf	fruit_on(a6)
next_game_turn
	cmpi.b	#246,num_dots_eaten(a6)	have all the dots been eaten
	beq	start_round		new round if so
	bra	game_turn		keep going with the game
**************************************************************************
_initial_round_values
	clr.b	num_dots_eaten(a6)	0 dots eaten at the start
	move.w	#2500,fruit_appear(a6)	fruit appears after x frames
	move.w	#4000,fruit_disappear(a6)
* work out speed and fruit values etc
	move.w	screen_num(a6),d0
	cmpi.w	#20,d0			screen 20 or more?
	blt.s	not_scr20_
	 move.w	#7,fruit_type(a6)	keys on this screen
	 clr.w	scrn_delay(a6)		0 delay, fast as possible
	 move.w	#10,ghost_blue(a6)	ghosts blue for only 10 frames
	 bra.s	done_init_rnd
not_scr20_
	cmpi.w	#12,d0
	blt.s	not_scr12_19
	 move.w	#7,fruit_type(a6)
	 clr.w	scrn_delay(a6)
	 move.w	#100,ghost_blue(a6)
	 bra.s	done_init_rnd
not_scr12_19
	add.w	d0,d0			double d0 for word offset
	move.w	fruit_codes(pc,d0.w),fruit_type(a6)
	move.w	scr_delays(pc,d0.w),scrn_delay(a6)
	move.w	blue_time(pc,d0.w),ghost_blue(a6)
done_init_rnd
	move.w  fruit_type(a6),d0
	add.w	d0,d0			double for word offset
	move.w	fruit_vals(pc,d0.w),fruit_value(a6)
	move.w	fruit_sprite_offset(pc,d0.w),fr_spr_off(a6)
	rts
* the scoring values of each of the 8 fruits
fruit_vals	
	dc.w	10,30,50,70,100,200,300,500
fruit_sprite_offset
	dc.w	0,104,208,312,416,520,624,728
* following tables contain data for screens 0-11
fruit_codes
	dc.w	0,1,2,2,3,3,4,4,5,5,6,6
scr_delays
	dc.w	8500,7000,7000,7000,3000,5000,3000,5000
	dc.w	3000,5000,3000,3000
blue_time
	dc.w	600,500,500,500,150,250,150,250,150,250,150,150
**************************************************************************
_move_speedy
	 movem.w speedy_data(a6),d4-d7
* find if the monster is not in the pen
	cmpi.w	#129,d4				
	blt.s	sd_int
	cmpi.w	#170,d4
	bge.s	sd_int
	cmpi.w	#75,d5
	blt.s	sd_int
	cmpi.w	#84,d5
	bge.s	sd_int	
	 move.w	#$747,H_PAL+26			back to pink
	 bsr	_pen_intelligence
	 bra.s	done_sd_move
sd_int
	move.w	d6,d0
	andi.w	#%11,d0
	tst.w	d0				normal, not blue or eyes?
	bne.s	sd_n_be
	 bsr	_less_intelligence
	 bra.s	done_sd_move
sd_n_be	cmpi.b	#%01,d0				eyes?
	bne.s	sd_n_e
	 bsr	_eye_intelligence
	 bra.s	done_sd_move
sd_n_e	bsr	_shy_intelligence		must be blue
done_sd_move
	movem.w d4-d7,speedy_data(a6)
	rts
**************************************************************************
_move_pokey
	movem.w pokey_data(a6),d4-d7
* find if the monster is not in the pen
	cmpi.w	#129,d4				
	blt.s	pk_int
	cmpi.w	#170,d4
	bge.s	pk_int
	cmpi.w	#75,d5
	blt.s	pk_int
	cmpi.w	#84,d5
	bge.s	pk_int	
	 move.w	#$730,H_PAL+4			back to orange
	 bsr	_pen_intelligence
	 bra.s	done_pk_move
pk_int
	move.w	d6,d0
	and.w	#%11,d0				mask low two bits
	tst.w	d0				not blue, not eyes?
	bne.s	pk_n_be
	 bsr.s	_intelligence
	 bra.s	done_pk_move
pk_n_be	cmpi.w	#%01,d0				eyes? 
	bne.s	pk_n_e
	 bsr	_eye_intelligence
	 bra.s	done_pk_move
pk_n_e	bsr	_shy_intelligence		must be blue
done_pk_move
	movem.w d4-d7,pokey_data(a6)	restore altered sprite data
	rts
**************************************************************************
_check_collision
	sf	d3			collision flag, off
	sub.w	d4,d0			check x distance
	blt.s	cc_abs_x
cc_x_ok	cmpi.w	#11,d0			are they closer than 16 pixels?
	bge.s	checked_collision	stop checking if far away
	 sub.w	d5,d1			check y distance
	 blt.s	cc_abs_y
cc_y_ok	 cmpi.w	#10,d1			closer than 12 pixels?
	  slt	d3			set d3 if there was a collision
checked_collision
	rts
cc_abs_x
	neg.w	d0
	bra.s	cc_x_ok
cc_abs_y
	neg.w	d1
	bra.s	cc_y_ok
**************************************************************************
* intelligence section for Shadow and Pokey
_intelligence
	bsr	_check_exits
	bsr	no_go_back
	movem.w	pacman_data(a6),d1-d2
* we now have d3: ....DURL with between 1 and 3 available directions
* eliminate some
sp_lr_choose
	move.b	d3,d0
	and.b	#%0011,d0
	tst.b	d0			both left and right possible?
	bne.s	sp_ud_choose		if not then nothing to do
	 cmp.w	d1,d4			is pacman to the left or right?
	 blt.s	sp_p_r
	  bset	#1,d3			pacman is left so don't go right
	  bra.s	sp_ud_choose
sp_p_r	 bset	#0,d3			pacman is right so don't go left
sp_ud_choose
	move.b	d3,d0
	and.b	#%1100,d0
	tst.b	d0			both up and down possible?
	bne.s	sp_choose2		if not then nothing to do
	 cmp.w	d2,d5			pacman up or down?
	 blt.s	sp_p_d
	  bset	#3,d3			pacman is up so don't go down
	  bra.s	sp_choose2
sp_p_d	 bset	#2,d3			pacman is down so don't go up
* now have a maximum of 2 directions
sp_choose2
	sub.w	d4,d1			how far away in x dir is pacman
	blt.s	sp_abs_x		make positive
sp_ps_x	sub.w	d5,d2			how far away in y dir is pacman
	blt.s	sp_abs_y		make positive
sp_ps_y	cmp.w	d1,d2
	bhi.s	sp_2
	bsr	ch_final_dir_1
	bra.s	sp_chosen
sp_2	bsr	ch_final_dir_2
sp_chosen
	rts
sp_abs_x
	neg.w	d1
	bra.s	sp_ps_x
sp_abs_y
	neg.w	d2
	bra.s	sp_ps_y
**************************************************************************
* less intelligence section for Speedy
_less_intelligence
	bsr	_check_exits
	bsr	no_go_back
* we now have d3: ....DURL with between 1 and 3 available directions
	move.w	#17,-(a7)		random()
	trap	#14			xbios
	addq.l	#2,a7			tidy
	move.w	d0,rnd_num(a6)
sd_lr_choose
	move.b	d3,d0
	and.b	#%0011,d0
	tst.b	d0			both left and right possible?
	bne.s	sd_ud_choose		if not then nothing to do
	 tst.w	rnd_num(a6)		50% chance
	 blt.s	sd_p_r
	  bset	#1,d3
	  bra.s	sd_ud_choose
sd_p_r	 bset	#0,d3
sd_ud_choose
	ror	rnd_num(a6)		new random number
	move.b	d3,d0
	and.b	#%1100,d0
	tst.b	d0			both up and down possible?
	bne.s	sd_choose2		if not then nothing to do
	 tst.w	rnd_num(a6)		50% chance
	 blt.s	sd_p_d
	  bset	#3,d3
	  bra.s	sd_choose2
sd_p_d	 bset	#2,d3
* now maximum of 2 directions
sd_choose2
	ror	rnd_num(a6)		new random number
	tst.w	rnd_num(a6)		50% chance
	blt.s	sd_ch_2
	 bsr	ch_final_dir_1
	 bra.s	sd_chosen
sd_ch_2	bsr	ch_final_dir_2
sd_chosen
	rts
**************************************************************************
_shy_intelligence
	bsr	_check_exits
	bsr	no_go_back
	movem.w	pacman_data(a6),d1-d2
* we now have d3: ....DURL with between 1 and 3 available directions
* eliminate some
bs_lr_choose
	move.b	d3,d0
	and.b	#%0011,d0
	tst.b	d0			both left and right possible?
	bne.s	bs_ud_choose		if not then nothing to do
	 cmp.w	d1,d4			is pacman to the left or right?
	 blt.s	bs_p_r
	  bset	#0,d3			pacman is left so don't go left
	  bra.s	bs_ud_choose
bs_p_r	 bset	#1,d3			pacman is right so don't go right
bs_ud_choose
	move.b	d3,d0
	and.b	#%1100,d0
	tst.b	d0			both up and down possible?
	bne.s	bs_choose2		if not then nothing to do
	 cmp.w	d2,d5			pacman up or down?
	 blt.s	bs_p_d
	  bset	#2,d3			pacman is up so don't go up
	  bra.s	bs_choose2
bs_p_d	 bset	#3,d3			pacman is down so don't go down
* maximum of 2 directions now, go as far away from pacman as possible
bs_choose2
	cmp.w	d1,d2
	bls.s	bs_ch_2
	bsr	ch_final_dir_1
	bra.s	bs_chosen
bs_ch_2	bsr	ch_final_dir_2
bs_chosen
	rts
**************************************************************************
_pen_intelligence
	and.b	#%11111100,d6		set not blue & not eyes
	bsr	_less_intelligence	move around randomly in pen
	rts
**************************************************************************
* intelligence section for when the ghosts are eyes returning to the pen
_eye_intelligence
	bsr	_check_all_dir
	bsr.s	no_go_back
* we now have d3: ....DURL with between 1 and 3 available directions
* eliminate some
ey_lr_choose
	move.b	d3,d0
	and.b	#%0011,d0
	tst.b	d0			both left and right possible?
	bne.s	ey_ud_choose		if not then nothing to do
	 cmpi.w	#150,d4			is the pen to the left or right?
	 blt.s	ey_p_r
	  bset	#1,d3			pen is left so don't go right
	  bra.s	ey_ud_choose
ey_p_r	 bset	#0,d3			pen is right so don't go left
ey_ud_choose
	move.b	d3,d0
	and.b	#%1100,d0
	tst.b	d0			both up and down possible?
	bne.s	ey_choose2		if not then nothing to do
	 cmpi.w	#75,d5			is the pen up or down?
	 blt.s	ey_p_d
	  bset	#3,d3			pen is up so don't go down
	  bra.s	ey_choose2
ey_p_d	 bset	#2,d3			pen is down so don't go up
* now have a maximum of 2 directions
ey_choose2
	subi.w	#150,d1			how far away in x dir is the pen
	blt.s	ey_abs_x		make positive
ey_x_ok	subi.w	#75,d2			how far away in y dir is the pen
	blt.s	ey_abs_y		make positive
ey_y_ok	cmp.w	d1,d2
	bhi.s	ey_2
	bsr.s	ch_final_dir_1
	bra.s	ey_chosen
ey_2	bsr.s	ch_final_dir_2
ey_chosen
	rts
ey_abs_x
	neg.w	d1
	bra.s	ey_x_ok	
ey_abs_y
	neg.w	d2
	bra.s	ey_y_ok
**************************************************************************
* make sure the ghost dosen't double back (applies to all of them)
no_go_back
	tst.w	d7		check current direction, left?
	bne.s	g_no_l
	 ori.w	#%0010,d3	can't turn 180deg and go right
	 bra.s	g_ode
g_no_l	cmpi.w	#1,d7		right?
	bne.s	g_no_r
	 ori.w	#%0001,d3	can't go left
	 bra.s	g_ode
g_no_r	cmpi.w	#2,d7		up?
	bne.s	g_no_u
	 ori.w	#%1000,d3	can't go down
	 bra.s	g_ode
g_no_u	cmpi.w	#3,d7		down?
	bne.s	g_ode
	 ori.w	#%0100,d3	can't go up
g_ode	rts
**************************************************************************
* actually decide on 1 final direction in the order L,R,U,D
ch_final_dir_1
	btst	#0,d3			left?
	bne.s	g1_nt_l
	 moveq	#0,d7			go left
	 bra.s	g1_ghost_go
g1_nt_l	btst	#1,d3			right?
	bne.s	g1_nt_r
	 moveq	#1,d7			go right
	 bra.s	g1_ghost_go
g1_nt_r	btst	#2,d3			up?
	bne.s	g1_nt_u
	 moveq	#2,d7			go up
	 bra.s	g1_ghost_go
g1_nt_u	btst	#3,d3			down?
	bne.s	done_g1_dir
	 moveq	#3,d7			go down
g1_ghost_go
	bsr.s	move_ghost
done_g1_dir
	rts
**************************************************************************
* actually decide on 1 final direction in the order D,U,R,L
ch_final_dir_2
	btst	#3,d3			down?
	bne.s	g2_nt_d
	 moveq	#3,d7			go down
	 bra.s	g2_ghost_go
g2_nt_d	btst	#2,d3			up?
	bne.s	g2_nt_u
	 moveq	#2,d7			go up
	 bra.s	g2_ghost_go
g2_nt_u	btst	#1,d3			right?
	bne.s	g2_nt_r
	 moveq	#1,d7			go right
	 bra.s	g2_ghost_go
g2_nt_r	btst	#0,d3			left?
	bne.s	done_g2_dir
	 moveq	#0,d7			go left
g2_ghost_go
	bsr.s	move_ghost
done_g2_dir
	rts
**************************************************************************
* actually move the ghost in the chosen direction
move_ghost
	tst.b	ghosts_stop(a6)		are the ghosts stopped?
	bne.s	g_end_tunnel		don't move them if so
	tst.b	d7			left (ie d7=%0000)
	bne.s	g_ng_l
	 subq.w	#SPRITE_SPEED,d4	x:=x-speed
	 bra.s	done_g_dir
g_ng_l	cmpi.b	#1,d7			right
	bne.s	g_ng_r
	 addq.w	#SPRITE_SPEED,d4	x:=x+speed
	 bra.s	done_g_dir
g_ng_r	cmpi.b	#2,d7			up
	bne.s	g_ng_u
	 subq.w	#SPRITE_SPEED,d5	y:=y-speed
	 bra.s	done_g_dir
g_ng_u	cmpi.b	#3,d7			down
	bne.s	done_g_dir
	 addq.w	#SPRITE_SPEED,d5	y:=y+speed
done_g_dir
* check if the ghost has gone through a tunnel
	cmpi.w	#32,d4			if x<=48 then out left tunnel
	bgt.s	g_no_lt_tunnel
	 move.w	#263,d4			put him on the right side
	 bra.s	g_end_tunnel	
g_no_lt_tunnel
	cmpi.w	#264,d4			if x>=264 then out right tunnel
	blt.s	g_end_tunnel
	 move.w	#33,d4			put him on the left side
g_end_tunnel
	rts
**************************************************************************
_pacman_dead
	do_snd	<dead_sound>		make a sad sound
	subq.w	#1,pacman_stats(a6)	pacman was got, reduce lives
	bsr	_long_delay
	rts
**************************************************************************
_energizer_on
	move.b	#8,ghosts_stop(a6)	ghosts stop for 8 frames
	move.w	ghost_blue(a6),energizer_time(a6)
	movea.l	#H_PAL,a0
	move.w	#$037,2(a0)		Shadow blue
	move.w	#$037,4(a0)		Pokey blue
	move.w	#$037,18(a0)		Bashful blue
	move.w	#$037,26(a0)		Speedy blue
* all (non eye) ghosts reverse directions
	lea	shadow_stats(a6),a0
	moveq	#3,d1			4 ghosts to do
rev_g_loop
	move.w	(a0),d0
	andi.w	#%11,d0
	tst.w	d0			normal? (ie d0=%00)
	bne.s	no_rev
	 move.w	2(a0),d0
	 bsr.s	_reverse_ghost
	 move.w	d0,2(a0)
no_rev	ori.w	#%10,(a0)		set stats, ghosts blue & not eyes
	addq.l	#8,a0			next ghost
	dbf	d1,rev_g_loop
	rts	
_reverse_ghost
	tst.w	d0			left? (ie d0=0)
	bne.s	gr_no_l
	 moveq	#1,d0			set right
	 bra.s	reversed_ghost
gr_no_l	cmpi.w	#1,d0			right?
	bne.s	gr_no_r
	 moveq	#0,d0			set left
	 bra.s	reversed_ghost
gr_no_r	cmpi.w	#2,d0			up?
	bne.s	gr_no_u	
	 moveq	#3,d0			set down
	 bra.s	reversed_ghost
gr_no_u	moveq	#2,d0			must be going down, set to up
reversed_ghost
	rts
**************************************************************************
_energizer_off
	movem.l	d0-d1/a0-a1,-(a7)
	do_snd	<stop_music>
	movem.l	(a7)+,d0-d1/a0-a1
	movea.l	#H_PAL,a0
	move.w	#$700,2(a0)		restore Shadow
	bclr	#1,shadow_stats+1(a6)
	move.w	#$730,4(a0)		restore Pokey
	bclr	#1,pokey_stats+1(a6)
	move.w	#$057,18(a0)		restore Bashful
	bclr	#1,bashful_stats+1(a6)
	move.w	#$747,26(a0)		restore Speedy
	bclr	#1,speedy_stats+1(a6)
	move.w	#20,ghost_value(a6)	reset ghost value
	rts
**************************************************************************
_flash_ghosts
	movea.l	#H_PAL,a0
	btst	#1,shadow_stats+1(a6)	Shadow blue?
	beq.s	sh_no_f
	 eori.w	#$740,2(a0)
sh_no_f	btst	#1,pokey_stats+1(a6)	Pokey blue?
	beq.s	pk_no_f
	 eori.w	#$740,4(a0)
pk_no_f	btst	#1,bashful_stats+1(a6)	Bashful blue?
	beq.s	bs_no_f
	 eori.w	#$740,18(a0)
bs_no_f	btst	#1,speedy_stats+1(a6)	Speedy blue?
	beq.s	sd_no_f
	 eori.w	#$740,26(a0)
sd_no_f	rts
**************************************************************************
* find all the directions that the sprite can move in
* 3530 cycles at worst
* in: d4.w=x d5.w=y
* out: d3=....DURL, where 1=wall,0=no wall
* uses: d0-1
_check_exits
	bsr.s	_check_all_dir
	cmpi.w	#148,d4			check if sprite is above the pen
	bne.s	chkd_exits		
	 cmpi.w	#62,d5
	 bne.s	chkd_exits
	  addq.w #8,d3			can't go down if so
* d3 now contains 0000DURL
chkd_exits
	rts
**************************************************************************
_check_all_dir
	moveq	#0,d3			directions stored in d3
	move.w	d4,d0			x
	move.w	d5,d1
	addq.w	#1,d1			y+1
	bsr	_point_test
	cmpi.b	#TRACK,d0	
	beq.s	left_not_blocked
	addq.w	#1,d3			...L
left_not_blocked
	move.w	d4,d0
	addq.w	#2,d0			x+2
	move.w	d5,d1
	addq.w	#1,d1			y+1
	bsr	_point_test	
	cmpi.b	#TRACK,d0
	beq.s	right_not_blocked
	addq.w	#2,d3			..R.
right_not_blocked
	move.w	d4,d0
	addq.w	#1,d0			x+1
	move.w	d5,d1			y
	bsr	_point_test	
	cmpi.b	#TRACK,d0
	beq.s	up_not_blocked
	addq.w	#4,d3			.U..
up_not_blocked
	move.w	d4,d0
	addq.w	#1,d0			x+1
	move.w	d5,d1
	addq.w	#2,d1			y+2
	bsr	_point_test	
	cmpi.b	#TRACK,d0
	beq.s	down_not_blocked
	addq.w	#8,d3			D...
down_not_blocked
	rts
**************************************************************************
* check if the pacman has eaten a dot
_check_dot_eaten
	move.w	d4,d0
	addq.w	#8,d0			x+8
	move.w	d5,d1
	addi.w	#6,d1			y+6
	bsr	_point_test
	cmpi.b	#DOT,d0
	beq.s	dot_eaten
	cmpi.b	#ENERGIZER,d0
	beq.s	energizer_eaten
	rts
**************************************************************************
dot_eaten
* note that its been eaten
	addq.b	#1,num_dots_eaten(a6)
* make the appropriate noise unless the energizer music is going
	tst.w	energizer_time(a6)
	bne.s	no_dot_noise
	 do_snd <dot_noise>
no_dot_noise
* rub out the dot
	move.w	d4,d0
	addq.w	#8,d0			x+8
	move.w	d5,d1
	addi.w	#6,d1			y+6
	moveq	#SPACE,d2		colour
	bsr	_point_set	
* increase the score by 10
	addq.l	#1,score(a6)
	bsr	_display_score
	rts
**************************************************************************
energizer_eaten
* note that its been eaten
	addq.b	#1,num_dots_eaten(a6)
* make the appropriate noise
	do_snd	<chase_music>
* rub out the energizer
	lea	energizer_dots(pc),a1
	cmpi.w	#156,d4				left or right
	blt.s	eng_left
	 cmpi.w	#100,d5				up or down
	 blt.s	e_rt_up
	  lea	252(a1),a1			right & down
	  bra.s	found_eng
e_rt_up	 lea	84(a1),a1			right & up
	 bra.s	found_eng
eng_left
	cmpi.w	#100,d5				up or down
	blt.s	found_eng
	 lea	168(a1),a1			left and down
found_eng
	moveq	#21,d3			21 dots make up 1 energizer
erase_eng_loop
	move.w	(a1)+,d0		x
	move.w	(a1)+,d1		y
	moveq	#SPACE,d2		colour
	move.w	d3,-(a7)		save loop counter as its corrupted
	bsr.s	_point_set
	move.w	(a7)+,d3		restore loop counter
	dbf	d3,erase_eng_loop	
* increase the score by 50
	addi.l	#5,score(a6)
	bsr	_display_score
	bsr	_energizer_on		effects on
	rts
**************************************************************************
_draw_all_dots	
	lea	all_dots(pc),a1
	moveq	#8,d5			y coords start at 8
dot_lines
	move.w	(a1)+,d4		get num of dots (-1) in this line
each_dot
	move.w	(a1)+,d0		get x value
	move.w	d5,d1			y value
	moveq	#DOT,d2			colour=DOT=white
	bsr.s	_point_set
	dbf	d4,each_dot		next dot in this line
	addq.w	#6,d5			next y value := y+6
	cmpi.w	#176,d5			last line is y=176
	ble.s	dot_lines		back for next line
* now draw energizers
	lea	energizer_dots(pc),a1
	moveq	#83,d4			84 dots make up 4 energizers
energizer_loop
	move.w	(a1)+,d0		x
	move.w	(a1)+,d1		y
	moveq	#ENERGIZER,d2		colour
	bsr.s	_point_set
	dbf	d4,energizer_loop
	rts	
	SECTION DATA
all_dots
	dc.w	23,56,64,72,80,88,96,104,112,120,128,136,144,168,176,184
	 dc.w	192,200,208,216,224,232,240,248,256
	dc.w	5,56,96,144,168,216,256
	dc.w	3,96,144,168,216		
	dc.w	5,56,96,144,168,216,256
	dc.w	25,56,64,72,80,88,96,104,112,120,128,136,144,152,160,168
	 dc.w	176,184,192,200,208,216,224,232,240,248,256
	dc.w	5,56,96,120,192,216,256
	dc.w	5,56,96,120,192,216,256
	dc.w	19,56,64,72,80,88,96,120,128,136,144,168,176,184,192,216
	 dc.w	224,232,240,248,256
	dc.w	1,96,216
	dc.w	1,96,216
	dc.w	1,96,216
	dc.w	1,96,216
	dc.w	1,96,216
	dc.w	1,96,216
	dc.w	1,96,216
	dc.w	1,96,216
	dc.w	1,96,216
	dc.w	1,96,216
	dc.w	1,96,216
	dc.w	23,56,64,72,80,88,96,104,112,120,128,136,144,168,176,184
	 dc.w	192,200,208,216,224,232,240,248,256
	dc.w	5,56,96,144,168,216,256
	dc.w	5,56,96,144,168,216,256
	dc.w	19,64,72,96,104,112,120,128,136,144,152,160,168,176,184
	 dc.w	192,200,208,216,240,248
	dc.w	5,72,96,120,192,216,240
	dc.w	5,72,96,120,192,216,240
	dc.w	19,56,64,72,80,88,96,120,128,136,144,168,176,184,192,216
	 dc.w	224,232,240,248,256
	dc.w	3,56,144,168,256
	dc.w	3,56,144,168,256
	dc.w	25,56,64,72,80,88,96,104,112,120,128,136,144,152,160,168
	 dc.w	176,184,192,200,208,216,224,232,240,248,256
energizer_dots
	dc.w	55,18,56,18,57,18,54,19,55,19,56,19,57,19,58,19,54,20
	dc.w	55,20,56,20,57,20,58,20,54,21,55,21,56,21,57,21,58,21
	dc.w	55,22,56,22,57,22
	dc.w	255,18,256,18,257,18,254,19,255,19,256,19,257,19,258,19
	dc.w	254,20,255,20,256,20,257,20,258,20,254,21,255,21,256,21
	dc.w	257,21,258,21,255,22,256,22,257,22
	dc.w	55,138,56,138,57,138,54,139,55,139,56,139,57,139,58,139
	dc.w	54,140,55,140,56,140,57,140,58,140,54,141,55,141,56,141
	dc.w	57,141,58,141,55,142,56,142,57,142
	dc.w	255,138,256,138,257,138,254,139,255,139,256,139,257,139
	dc.w	258,139,254,140,255,140,256,140,257,140,258,140,254,141
	dc.w	255,141,256,141,257,141,258,141,255,142,256,142,257,142
	SECTION TEXT
**************************************************************************
* routine equivalent to line-a pset
* 290-298 cycles
* in:	d0=x d1=y d2=colour a4=background screen
* out:
* changes: d0-3,a0
_point_set
	ext.l	d1			extend y value to 32 bits
	move.w	d1,d3			copy y
	add.w	d1,d1			*2
	add.w	d1,d1			*4
	add.w	d3,d1			*5
	lsl.w	#5,d1			*5*32 = y*160
	move.w	d0,d3			copy x
	ext.l	d3			extend x to 32 bits
	and.w	#$fff0,d3
	asr.w	#1,d3
	add.l	d3,d1			total offset in d1
	and.w	#$000f,d0
	movea.l	backbase(a6),a0
	adda.w	d1,a0			screen address+disp in a0
	eori.w	#$f,d0
	clr.w	d1
	bset	d0,d1
	move.w	d1,d0
	not.w	d0
	moveq	#4-1,d3
pset_loop
	ror.w	#1,d2
	bcc.s	pset_clr_bit
	or.w	d1,(a0)+
	dbf	d3,pset_loop
	rts
pset_clr_bit
	and.w	d0,(a0)+
	dbf	d3,pset_loop
	rts
**************************************************************************
* routine equivalent to line-a ptst
* 238-246 cycles.  
* in:	d0.w=x, d1.w=y, a4=addr of background screen
* out: 	d0=colour	
* uses: d0-2,a0
_point_test
	move.w	d1,d2			copy y
	add.w	d1,d1			*2
	add.w	d1,d1			*4
	add.w	d2,d1			*5
	lsl.w	#5,d1			*5*32 = y*160
	move.w	d0,d2			copy x
	and.w	#$fff0,d2
	asr.w	#1,d2
	add.w	d2,d1			total offset in d1
	and.w	#$000f,d0
	movea.l	backbase(a6),a0
	lea	8(a0,d1.w),a0		screen address+8+disp in a0
	eori.w	#$f,d0
	clr.w	d1
	bset	d0,d1
	moveq	#0,d0			clear d0 ready for colour
* calculate each of the 4 bit planes					
	move.w	-(a0),d2		get word from the screen
	and.w	d1,d2			mask all except wanted bit
	sne	d2
	add.b	d2,d2
	addx.w	d0,d0			double d0 and add the bit value
	move.w	-(a0),d2		get word from the screen
	and.w	d1,d2			mask all except wanted bit
	sne	d2
	add.b	d2,d2
	addx.w	d0,d0			double d0 and add the bit value
	move.w	-(a0),d2		get word from the screen
	and.w	d1,d2			mask all except wanted bit
	sne	d2
	add.b	d2,d2
	addx.w	d0,d0			double d0 and add the bit value
	move.w	-(a0),d2		get word from the screen
	and.w	d1,d2			mask all except wanted bit
	sne	d2
	add.b	d2,d2
	addx.w	d0,d0			double d0 and add the bit value
* the colour value is now in d0
	rts
**************************************************************************
* Display all necessary sprites on the screen
**************************************************************************
_display_sprites
* first the fruit as everything else goes over the top of it
	tst.b	fruit_on(a6)		is the fruit visible?
	beq.s	display_pacman		don't display if not
	 movea.l logbase(a6),a0		screen
	 move.w	fr_spr_off(a6),d0	offset
	 lea	s_fruit(pc),a1		base address of fruit sprites
	 adda.w	d0,a1			add the offset
	 move.w	#148,d4			x position
	 moveq	#98,d5			y_position
	 moveq	#12,d2			13 lines high
	 bsr	_display_sprite_16 
display_pacman
	movem.w	pacman_data(a6),d4-d7
	lea	s_pacman(pc),a1		a1 holds address of sprite data
	bsr.s	_sprite_direction
* then pokey
	movem.w	pokey_data(a6),d4-d7
	btst	#0,d6			is he eaten
	beq.s	pk_no_i
	 lea	s_eyes(pc),a1
	 bsr.s	_eyes_direction
	 bra.s	display_shadow
pk_no_i	lea	s_pokey(pc),a1		a1 holds address of sprite data
	bsr.s	_sprite_direction
display_shadow
	movem.w	shadow_data(a6),d4-d7
	btst	#0,d6
	beq.s	sh_no_i
	 lea	s_eyes(pc),a1
	 bsr.s	_eyes_direction
	 bra.s	display_bashful
sh_no_i	lea	s_shadow(pc),a1		a1 holds address of sprite data
	bsr.s	_sprite_direction
display_bashful
	movem.w	bashful_data(a6),d4-d7
	btst	#0,d6
	beq.s	bs_no_i
	 lea	s_eyes(pc),a1
	 bsr.s	_eyes_direction
	 bra.s	display_speedy
bs_no_i	lea	s_bashful(pc),a1	a1 holds address of sprite data
	bsr.s	_sprite_direction
display_speedy
	movem.w	speedy_data(a6),d4-d7
	btst	#0,d6
	beq.s	sd_no_i
	 lea	s_eyes(pc),a1
	 bsr.s	_eyes_direction
	 bra.s	finished_displaying
sd_no_i	lea	s_speedy(pc),a1		a1 holds address of sprite data
	bsr.s	_sprite_direction
finished_displaying
	rts
* find correct sprite for the direction
* in: d4-d7=spite data, a1=addr of sprite
_sprite_direction
	add.w	d7,d7			double d7 for word offset
	move.w	sprite_offset(pc,d7.w),d7 offset for correct direction
	adda.w	d7,a1
	movea.l	logbase(a6),a0		screen
	moveq	#12,d2			sprites are 13 lines high
	bsr.s	_display_sprite_16
	rts
* this small table represents 104*dir, where 0<=dir<=3 
sprite_offset
	dc.w	0,104,208,312
_eyes_direction
	add.w	d7,d7			double d7 for word offset
	move.w	eyes_offset(pc,d7.w),d7 offset for correct direction
	adda.w	d7,a1
	movea.l	logbase(a6),a0
	moveq	#7,d2			eyes are 8 lines high
	bsr.s	_display_sprite_16
	rts
* this small table represents 64*dir, where 0<=dir<=3 
eyes_offset
	dc.w	0,64,128,192
**************************************************************************
* Handle one complete 16x16 sprite: calculate position, then draw
* in	d2: sprite height - 1
*	d4: sprite x co-ordinate
*	d5: sprite y co-ordinate
*	a0: pointer to base of screen
*	a1: pointer to sprite data
* uses	d1: working
*	a0: pointer to screen position of sprite
* corrupts:	d0-d7,a0-a1

_display_sprite_16
	move.w	d5,d0		* d5 by 160: first make a copy
	add.w	d5,d5		*2
	add.w	d5,d5		*4
	add.w	d0,d5		*5
	lsl.w	#5,d5		*5*32, now we have d5*160
	move.l	d4,d1		calculate x offset		
	andi.w	#15,d1		find spr_x mod 16, use for rotations
	lsr.w	#1,d4		divide x by 2
	andi.b	#%11111000,d4	make sure it's a multiple of 8	
	add.w	d4,d5		(sprite x offset) + (sprite y offset)
	lea	0(a0,d5.w),a0	screen base + offset in a0

* The actual sprite drawing bit
* in:	d2: height of sprite - 1   
*	a0: the sprite's position in screen memory
* uses: d0: sprite mask
*       d4: sprite plane 0
*       d5: sprite plane 1
*       d6: sprite plane 2
*       d7: sprite plane 3

draw_all_16
	moveq	#0,d4		clear all 32 bits of the registers
	moveq	#0,d5
	moveq	#0,d6
	moveq	#0,d7
	movem.w	(a1)+,d4-d7	read sprite block, planes 0 to 3
	ror.l	d1,d4		rotate plane 0
	ror.l	d1,d5		rotate plane 1
	ror.l	d1,d6		rotate plane 2
	ror.l	d1,d7		rotate plane 3
	move.l	d4,d0		make the mask
	or.l	d5,d0
	or.l	d6,d0
	or.l	d7,d0
	not.l	d0
	and.w	d0,(a0)		mask the background
	or.w	d4,(a0)+	combine with the sprite, bitplane 0
	and.w	d0,(a0)		mask the background
	or.w	d5,(a0)+	combine with the sprite, bitplane 1
	and.w	d0,(a0)		mask the background
	or.w	d6,(a0)+	combine with the sprite, bitplane 2
	and.w	d0,(a0)		mask the background
	or.w	d7,(a0)+	combine with the sprite, bitplane 3
	swap	d0		
	swap	d4		swap high and low words so that the
	swap	d5		  low words can be displayed
	swap	d6
	swap	d7
	and.w	d0,(a0)		mask the background
	or.w	d4,(a0)+	combine with the sprite, bitplane 0
	and.w	d0,(a0)		mask the background
	or.w	d5,(a0)+	combine with the sprite, bitplane 1
	and.w	d0,(a0)		mask the background
	or.w	d6,(a0)+	combine with the sprite, bitplane 2
	and.w	d0,(a0)		mask the background
	or.w	d7,(a0)+	combine with the sprite, bitplane 3
	lea	144(a0),a0	move to next line
	dbf	d2,draw_all_16	draw next line of sprite
	rts
**************************************************************************	
* corrupts:	d0
_display_score
	movem.l	d1-d4/a0-a1,-(a7)
	bsr	_erase_score
	clr.w	d0			x position of the score
	move.l	score(a6),d4
	bsr.s	_write_score
	movem.l	(a7)+,d1-d4/a0-a1
	rts
**************************************************************************	
* corrupts:	d0-d4,a0,a1
_display_hiscore
	bsr	_erase_hiscore		
	move.w	#272,d0			x position of the high score
	move.l	hiscore(a6),d4
	bsr.s	_write_score
	rts
**************************************************************************	
* changes the score display on the background screen
* this is later copied to the logical screen
* in:	d0=the x position of the score, d4=the actual score
* corrupts:	d0-d4
_write_score
* draw the new score
sc_5	cmpi.l	#100000,d4		get rid of any 100,000s
	blt.s	sc_4
	 subi.l	#100000,d4
	 bra.s	sc_5
sc_4	moveq	#0,d3
sc_4c	cmpi.l	#10000,d4		check for 10,000s
	blt.s	sc_3
	 addq.w	#1,d3
	 subi.l	#10000,d4
	 bra.s	sc_4c
sc_3	move.w	#34,d1
	move.w	d3,d2
	bsr.s	_text
	moveq	#0,d3
sc_3c	cmpi.w	#1000,d4		check for 1,000s
	blt.s	sc_2
	 addq.w	#1,d3
	 subi.w	#1000,d4
	 bra.s	sc_3c
sc_2	addq.w	#7,d0
	move.w	#34,d1
	move.w	d3,d2
	bsr.s	_text
	moveq	#0,d3
sc_2c	cmpi.w	#100,d4			check for 100s
	blt.s	sc_1
	 addq.w	#1,d3
	 subi.w	#100,d4
	 bra.s	sc_2c
sc_1	addq.w	#7,d0
	move.w	#34,d1
	move.w	d3,d2
	bsr.s	_text
	moveq	#0,d3
sc_1c	cmpi.w	#10,d4			check for 10s
	blt.s	sc_0
	 addq.w	#1,d3
	 subi.w	#10,d4
	 bra.s	sc_1c
sc_0	addq.w	#7,d0
	move.w	#34,d1
	move.w	d3,d2
	bsr.s	_text
	moveq	#0,d3
sc_0c	tst.w	d4			check for 1s (ie d4=0?)
	beq.s	sc_done
	 addq.w	#1,d3
	 subq.w	#1,d4
	 bra.s	sc_0c
sc_done	addq.w	#7,d0
	move.w	#34,d1
	move.w	d3,d2
	bsr.s	_text
	addq.w	#7,d0			print final '0'
	move.w	#34,d1
	moveq	#0,d2
	bsr.s	_text
	rts
**************************************************************************	
* routine to immitate line-a: pchar x,y,char
* in:		d0=x,d1=y,d2=num
* uses:		d0-5,a0-1 
* corrupts: 	d0-2/a0-1
_text	
	movem.l	d0/d3-d5,-(a7)			save registers
	move.w	d0,d3				x
	move.w	d1,d4				y
	move.w	d2,d5				num
	moveq	#0,d0
	lea	digits(pc),a0
	move.w	d5,d0				number
	andi.w	#$ff,d0				byte only
	move.w	d0,d1
	lsl.w	#3,d0				*8
	add.w	d1,d0				*9
	add.w	d1,d0				*10 (offset)
	add.l	d0,a0				digit offset
	movea.l	backbase(a6),a1			print to background screen
	move.w	d4,d0				y
	move.w	d0,d1
	add.w	d0,d0
	add.w	d0,d0
	add.w	d1,d0
	lsl.w	#5,d0
	move.w	d3,d1				x
	move.w	d1,d2
	andi.l	#15,d2				d2=rotations
	lsr.w	#1,d1
	andi.b	#$f8,d1
	add.w	d1,d0
	add.l	d0,a1				a1=screen offset
	moveq	#4,d3				5 lines to do
draw_character
	moveq	#0,d1
	move.w	(a0)+,d1			character line
	ror.l	d2,d1
	move.l	d1,d0
	not.l	d0				make mask
	and.w	d0,(a1)				mask the character
	or.w	d1,(a1)+			plane 0
	and.w	d0,(a1)				mask the character
	or.w	d1,(a1)+			plane 1
	and.w	d0,(a1)				mask the character
	or.w	d1,(a1)+			plane 2
	and.w	d0,(a1)				mask the character
	or.w	d1,(a1)+			plane 3
	swap	d0
	swap	d1
	and.w	d0,(a1)				mask the character
	or.w	d1,(a1)+			plane 0
	and.w	d0,(a1)				mask the character
	or.w	d1,(a1)+			plane 1
	and.w	d0,(a1)				mask the character
	or.w	d1,(a1)+			plane 2
	and.w	d0,(a1)				mask the character
	or.w	d1,(a1)+			plane 3
	lea	144(a1),a1			next line
	dbf	d3,draw_character
	movem.l	(a7)+,d0/d3-d5
	rts	
**************************************************************************	
_game_over
	lea	game_over(pc),a0
	move.l	physbase(a6),a1
	adda.l	#13176,a1		position (112,82)
	moveq	#8,d0			9 lines high
d_gmov_loop
	moveq	#6-1,d1			6*4=24 words per line
d_gmov_wds
	movem.w	(a0)+,d2-d5		
	move.w	d2,d6			make a mask
	or.w	d3,d6
	or.w	d4,d6
	or.w	d5,d6
	not.w	d6
	and.w	d6,(a1)
	or.w	d2,(a1)+
	and.w	d6,(a1)
	or.w	d3,(a1)+
	and.w	d6,(a1)
	or.w	d4,(a1)+
	and.w	d6,(a1)
	or.w	d5,(a1)+	
	dbf	d1,d_gmov_wds
	lea	112(a1),a1		next screen line
	dbf	d0,d_gmov_loop
	bsr	_get_any_key
	rts
**************************************************************************	
* load a compressed, low res, Degas screen
* in:		a0=addr of filename, a1=addr to write to
* uses:		d0-d2=general loop & working, d3=scan line loop
*		d4=plane loop, d5=next line start, d6=file handle
*		a0=used by fread(), a1=buffer, a2=screen
* corrupts:	d0-d6,a0-a3
_load_pc1
* first load the file to the logical screen
	move.l	a1,-(a7)		save addr
	clr.w	-(a7)			open file for reading
	move.l	a0,-(a7)		addr of filename
	move.w	#$3d,-(a7)		f_open
	trap	#1
	addq.l	#8,a7
	move.w	d0,d6			handle in d6
	tst.l	d0			error if d0 negative
	bge.s	load_ok
	 addq.l	#8,a7			get rid of ret addr & save addr
	 bra	finish			quit the program right now
load_ok
	move.l	logbase(a6),-(a7)	load to logbase
	move.l	#32000,-(a7)		32000 bytes max
	move.w	d6,-(a7)		handle
	move.w	#$3f,-(a7)		f_read
	trap	#1
	lea	12(a7),a7
	movea.l	(a7)+,a1		restore addr
* process the file
	movea.l	logbase(a6),a0
*	lea	34(a0),a0		skip over palette data etc
	moveq	#0,d3			scan line offset, 0 to 31840
scanline_loop
	moveq	#0,d4			plane offset, 0 to 6
plane_loop
	movea.l	a1,a2			base address of screen
	adda.l	d3,a2			+ scan line offset
	adda.l	d4,a2			+ plane offset
	move.l	a2,d5			nextline = addr + 160
	addi.l	#160,d5
bytes_loop
	moveq	#0,d2
	move.b	(a0)+,d2
	cmpi.b	#128,d2			check if >128,<128,=128
	bhi.s	gt_128_decompact
	beq.s	next_byte
* this section handles copying bytes exactly
copy_literal_loop
	 move.b	(a0)+,(a2)		move 1 byte to screen
	 bsr.s	_inc_addr
	 dbf	d2,copy_literal_loop
	 bra.s	next_byte
* this section handles copying 1 byte repeatedly - decompacting
gt_128_decompact
	neg.b	d2
	move.b	(a0)+,d1		byte to copy in d1
copy_byte_loop
	move.b	d1,(a2)			copy 1 byte to screen
	bsr.s	_inc_addr
	dbf	d2,copy_byte_loop
* now increase all the offsets and check if we've finished
next_byte
	cmp.l	a2,d5			test(nextline-line)
	bgt.s	bytes_loop
	addq.w	#2,d4			increase plane offset
	cmpi.w	#6,d4			loop until plane>3 (ie offset >6)
	ble.s	plane_loop
	add.w	#160,d3			increase scan line offset
	cmpi.w	#32000,d3		loop until scanline>199
	blt.s	scanline_loop
* close the file
	move.w	d6,-(a7)		handle
	move.w	#$3e,-(a7)		f_close
	trap	#1
	addq.l	#4,a7
	rts
* subroutine to increase the adrress to either the next byte or next plane
_inc_addr
	move.w	a2,d0			copy the address
	btst	#0,d0			is it odd?
	beq.s	inc_addr_even	
	 addq.l #6,a2			it's odd so add 6+1 (=7) to it
inc_addr_even
	addq.l	#1,a2			it's even so only add 1
	rts
**************************************************************************	
* in:	a4: addr of background screen
* corrupts:	d0,a0-a2
_copy_background_over
	move.l	backbase(a6),a0
	move.l	physbase(a6),a1
	move.l	logbase(a6),a2
	move.w	#7999,d0
copy_back_loop	
	move.l	(a0),(a1)+
	move.l	(a0)+,(a2)+
	dbf	d0,copy_back_loop
	rts
**************************************************************************	
_new_status_line
* first clear the old one
	movea.l	backbase(a6),a0
	lea	29760(a0),a0		start at line 186
	moveq	#12,d0			13 lines to clear
clr_stat_ln
	moveq	#39,d1			40 long words per line
clr_stat_wrd
	clr.l	(a0)+
	dbf	d1,clr_stat_wrd
	dbf	d0,clr_stat_ln
* draw pacmen to indicate lives
	cmpi.w	#2,pacman_stats(a6)	at least 2 lives?
	blt.s	dr_no_lives
	 lea	s_pacman(pc),a1
	 moveq	#46,d4			x
	 move.w	#186,d5			y
	 moveq	#12,d2			height
	 movea.l backbase(a6),a0	screen
	 bsr	_display_sprite_16
	cmpi.w	#3,pacman_stats(a6)
	blt.s	dr_no_lives		3 lives?
	 lea	s_pacman(pc),a1
	 moveq	#60,d4			x
	 move.w	#186,d5			y
	 moveq	#12,d2			height
	 movea.l backbase(a6),a0	screen
	 bsr	_display_sprite_16
dr_no_lives
* draw the required amount of fruit
* d1=screen to start at	
	moveq	#0,d1			default to screen 0 as start
	move.w	screen_num(a6),d0	what screen are we on?
	cmpi.w	#7,d0			is it above screen 6
	blt.s	scr_less_7
	 move.w	d0,d1			start 6 below current
	 subq.w	#6,d1			so as to draw 7 fruits only
scr_less_7
	move.w	#252,d4			start at x=252
	move.w	#186,d5			y is always 186
	moveq	#12,d2			height always 12
	move.w	screen_num(a6),d3	current screen number, stop here
fruit_loop
	move.w	d1,d0			d1 is the screen number
	bsr.s	_fruit_offset
	adda.l	d0,a2			add mask offset
	lea	s_fruit(pc),a1
	lsl.w	#2,d0			* d0 by 4, sprites have 4 planes
	adda.l	d0,a1			add sprite offset
	movem.l	d1-d5,-(a7)
	movea.l	backbase(a6),a0	screen
	bsr	_display_sprite_16
	movem.l	(a7)+,d1-d5	
	subi.w	#16,d4			next fruit is 16 pixels left
	addq.w	#1,d1			next screen
	cmp.w	d3,d1			past the current screen
	ble.s	fruit_loop		keep going until so	
	rts
**************************************************************************	
* in:	d0.w=screen number
* out:	d0.l=fruit offset
_fruit_offset
	cmpi.w	#12,d0			screen 12 or more?
	blt.s	fruit_not_key
	 move.w	#182,d0			keys on this screen
	 bra.s	done_f_off
fruit_not_key
	add.w	d0,d0			double d0 for word offset
	move.w	fruit_offsets(pc,d0.w),d0
done_f_off
	ext.l	d0			make sure it's 32 bits long
	rts
fruit_offsets
	dc.w	0,26,52,52,78,78,104,104,130,130,156,156
**************************************************************************	
* get rid of all 5 sprites and the score by drawing over them
* corrupts:	a2,d4,d5
_clear_screen
	lea	old_spr_data,a2
	movem.w	pacman_data(a2),d4-d5
	bsr.s	_erase_sprite
	movem.w	pokey_data(a2),d4-d5
	bsr.s	_erase_sprite
	movem.w	shadow_data(a2),d4-d5
	bsr.s	_erase_sprite
	movem.w	bashful_data(a2),d4-d5
	bsr.s	_erase_sprite
	movem.w	speedy_data(a2),d4-d5
	bsr.s	_erase_sprite
	move.w	#148,d4				erase fruit
	moveq	#98,d5
	bsr.s	_erase_sprite
* move score from background to logical screen
	bsr	_copy_score
	rts
**************************************************************************	
* draw over the sprite with a square from the background.
* assume height is 13
* in: d4=x, d5=y
* uses: d0,a0,a1
* corrupts:	d0,d4,d5,a0,a1
_erase_sprite
	move.w	d5,d0		* d5 by 160: first make a copy
	add.w	d5,d5		*2
	add.w	d5,d5		*4
	add.w	d0,d5		*5
	lsl.w	#5,d5		*5*32, now we have d5*160
	lsr.w	#1,d4		divide by 2
	andi.b	#%11111000,d4	make sure it's a multiple of 8
	add.w	d4,d5		(sprite x offset) + (sprite y offset)
	movea.l	logbase(a6),a1
	movea.l	backbase(a6),a0
	adda.w	d5,a1
	adda.w	d5,a0
* 13 lines to do
	REPT	12
	move.l	(a0)+,(a1)+	lines 1 to 12
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	lea	144(a1),a1
	lea	144(a0),a0
	ENDR
	move.l	(a0)+,(a1)+	line 13
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	rts
**************************************************************************	
* corrupts:	a0
_erase_score
* score assumed to start at (0,34) => offset = 0/2+160*34 = 5440
	movea.l	backbase(a6),a0
	lea	5440(a0),a0		offset to background
erase_score_loop
	REPT	6
	clr.l	(a0)+			clear to black
	clr.l	(a0)+
	clr.l	(a0)+
	clr.l	(a0)+
	clr.w	(a0)+			clear & draw some wall
	move.w	#%0000000000000001,(a0)+
	clr.w	(a0)+
	move.w	#%0000000000000001,(a0)+
	lea	136(a0),a0	move to next line
	ENDR
	rts
**************************************************************************	
* corrupts:	d0,a0
_erase_hiscore
* x=272, y=34 => offset = 272/2+34*160 = 5576
	movea.l	backbase(a6),a0
	lea	5576(a0),a0	 	position on background screen
	moveq	#5,d0			6 lines to do
erase_hiscore_loop
	clr.l	(a0)+				clear to black
	clr.l	(a0)+
	clr.l	(a0)+
	clr.l	(a0)+
	clr.l	(a0)+
	clr.l	(a0)+
	lea	136(a0),a0			move to next line
	dbf	d0,erase_hiscore_loop
	rts
**************************************************************************	
* this routine assumes the score is at (0,34)
* corrupts:	a0,a1
_copy_score
	movea.l	logbase(a6),a1
	lea	5440(a1),a1
	movea.l	backbase(a6),a0
	lea	5440(a0),a0
* 6 lines to do
	REPT	5
	move.l	(a0)+,(a1)+		lines 1 to 5
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	lea	136(a1),a1
	lea	136(a0),a0
	ENDR
	move.l	(a0)+,(a1)+		6th line
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	move.l	(a0)+,(a1)+
	rts
**************************************************************************	
* in:		a3=addr of string to print (nul terminated)
* corrupts:	d0-d2,a0-a2
_print
	tst.b	(a3)			NUL character for end of string
	beq.s	end_string
	moveq	#0,d0
	move.b	(a3)+,d0
	move.w	d0,-(a7)		character
	move.l	#$30002,-(a7)		b_conout to screen
	trap	#13			bios
	addq.l	#6,a7			tidy
	bra.s	_print
end_string
	rts
**************************************************************************	
* corrupts:	d0-d3,a0-a2
_get_any_key
	inkey
	tst.b	d0			was a character returned?			
	bne.s	_get_any_key		loop until buffer is clear
	moveq	#-1,d3			time counter
get_any_key
	addq.l	#1,d3			increase timer
	cmpi.l	#$7fffffff,d3		have we been waiting long enough
	bne.s	no_key_snd	
	 do_snd	<intro_song>
no_key_snd	
	btst.b	#1,KB_CONTROL		is keyboard ready for command
	beq.s	get_any_key		no, loop
	move.b	#$16,KB_DATA		request a joystick packet
	tst.b	fire
	bne.s	got_a_key
	inkey
	swap	d0			get scan code
	cmpi.b	#$61,d0			[Undo] to end
	beq	finish
	swap	d0			get ascii code back
	tst.b	d0			key pressed?
	beq.s	get_any_key		try again if not
got_a_key
	rts
**************************************************************************	
_get_key_colour
	inkey
	tst.b	d0			was a character returned?			
	bne.s	_get_key_colour		loop until buffer is clear
get_key_colour
	btst.b	#1,KB_CONTROL		is keyboard ready for command
	beq.s	get_key_colour		no, loop
	move.b	#$16,KB_DATA		request a joystick packet
	tst.b	fire
	bne.s	got_key_col
	addq.w	#1,H_PAL+4		cycle colours
	inkey
	swap	d0			get scan code
	cmpi.b	#$61,d0			[Undo] to quit
	beq	finish
	swap	d0			get ascii code back
	tst.b	d0			what key did we get?
	beq.s	get_key_colour		try again if nothing
got_key_col
	rts
**************************************************************************
_delay
	move.l	d0,-(a7)
	move.w	#10000,d0
delay_loop
	mulu	#1,d0
	dbf	d0,delay_loop
	move.l	(a7)+,d0
	rts
**************************************************************************
_long_delay
	movem.l	d0-d7/a0-a6,-(a7)
	moveq	#17,d1
delay_loop2
	moveq	#-1,d0			d0=$ffffffff
delay_loop1
	dbf	d0,delay_loop1
	dbf	d1,delay_loop2
	movem.l	(a7)+,d0-d7/a0-a6
	rts
**************************************************************************	
_short_delay
	move.l	d0,-(a7)
	move.w	#4000,d0
short_del_loop
	dbf	d0,short_del_loop
	move.l	(a7)+,d0
	rts
**************************************************************************	
_screen_delay
	move.w	d0,-(a7)		save d0 so nothing is changed
	move.w	scrn_delay(a6),d0
scrn_del_loop
	dbf	d0,scrn_del_loop
	move.w	(a7)+,d0		restore d0
	rts	
**************************************************************************	
	SECTION DATA
def_pal		dc.w	$000,$700,$730,$750,$770,$470,$105,$701
		dc.w	$740,$367,$027,$000,$507,$747,$777,$777
title_pal	dc.w	$000,$700,$770,$769,$7d3,$7c4,$74d,$737	
		dc.w	$467,$356,$345,$235,$224,$123,$113,$777
digits
		include	'A:\DIGITS09.S'
backfile	dc.b	'P_A_C_MZ.PC1',0
instructions	
	dc.b	27,'Y',39,42,'*** INSTRUCTIONS ***'
	dc.b	27,'Y',41,40,'Press any key now to play'
	dc.b	27,'Y',43,43,'During the game:'
	dc.b	27,'Y',44,40,'[Undo] to exit'
	dc.b	27,'Y',45,40,'Joystick controls movement'
	dc.b	27,'Y',50,34,'Comments/advice (money!) to:'
	dc.b	27,'Y',52,36,'W.Barnes. PO Box 599, Sandy Bay,'
	dc.b	27,'Y',53,40,'Tasmania, Australia 7005'
	dc.b	27,'Y',56,42,189,' Warwick Barnes 1991',0

	EVEN
	include	'A:\SPRITES.DAT\ALL_SPRT.S'
game_over
	include	'A:\GRAPHICS\GAMEOVER.S'
stop_music	dc.b	7,$ff,8,$00,9,$00,10,$00,130,0
dead_sound	dc.b	7,$fe,8,$0c,128,140,129,0,1,10,130,1,130,0
fruit_sound	dc.b	7,$fe,8,$0c,128,160,129,0,-10,10,130,1
dot_noise	dc.b	0,$aa,1,$00,6,$00,7,$fe,8,$10,9,$00,10,$00
		dc.b	11,$6d,12,$01,13,$00,130,0
intro_song
	incbin	'A:\SOUND\PACINTRO.XBS'
chase_music
	incbin	'A:\SOUND\PACCHASE.XBS'
title_screen
	incbin	'A:\GRAPHICS\TITLESCR.IMG'
**************************************************************************
	SECTION BSS
	EVEN
all_data	ds.b	var_length
old_spr_data	ds.b	40
dxy_joy
dx_joy		ds.w	1
dy_joy		ds.w	1
vbi_done	ds.b	1
fire		ds.b	1
	EVEN
log_scr		ds.b	32255	
back_scr	ds.b	32000

	END